﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "TemporaryDimensionHandler.h"
#include "UiViewUtils.h"
#include "Vector3dUtils.h"
#include "IUiDocumentViewManager.h"
#include "IUiManager.h"
#include "IApplicationWindow.h"
#include "IUiView.h"
#include "JournalUtils.h"
#include "IJournalUiObject.h"
#include "ITemporaryDimensionContext.h"
#include "Coordinate3d.h"

#include <QVariant>

#ifdef _WINDOWS
#include <imm.h>
#endif // _WINDOWS

#include <QLineEdit>
#include <QStyleFactory>
#include <QPalette>
#include "GcmpUiQtImpl.h"
#include "BalloonTipManager.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

#ifdef _WINDOWS
    #pragma comment(lib, "imm32.lib")
#endif // _WINDOWS

//////////////////////////////////////////////////////////////////////////
// HelperEditor
TemporaryDimensionHandleEditor::TemporaryDimensionHandleEditor(QWidget* parent) 
    : QLineEdit(parent) 
    , m_hasNothingToHandle(true)
{
    
}

TemporaryDimensionHandleEditor::~TemporaryDimensionHandleEditor()
{

}


//////////////////////////////////////////////////////////////////////////
// ElementEditHelper

TemporaryDimensionHandler::TemporaryDimensionHandler(gcmp::IUiView* pUIView)
    : m_uiViewId(pUIView->GetId())
    , m_pEditor(nullptr)
    , m_InputState(InputState::None)
    , m_TmpDimData(TemporaryDimensionData())
    , m_TmpDimStyle(TemporaryDimensionStyle())
    , m_lenValidator(gcmp::Constants::MIN_MODEL_SIZE, gcmp::Constants::MAX_MODEL_SIZE)
    , m_angValidator(-180.0, 180.0)
    , m_isUserCustomInput(false)
{
    DBG_WARN_UNLESS(pUIView != nullptr, L"m_pUIView指针不能为空",L"GDMPLab",L"2024-03-30");

    // 禁用输入法
    DisableIme();
}

TemporaryDimensionHandler::~TemporaryDimensionHandler(void)
{
    // 恢复输入法
    EnableIme();
    HideInputWidget();
}


void TemporaryDimensionHandler::HideInputWidget()
{
    m_InputState = InputState::None;
    if (m_pEditor)
    {
        m_pEditor->clearFocus();
        m_pEditor->hide();
        BalloonTipManager::GetInstance().Clear();
    }
}

bool gcmp::TemporaryDimensionHandler::UpdateConfig(const ITemporaryDimensionContext * pCtx)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pCtx, L"pCtx为空。",L"GDMPLab",L"2024-03-30");
    this->SetValidRangeOfLength(pCtx->GetValidRangeOfLength());
    this->SetValidRangeOfAngle(pCtx->GetValidRangeOfAngle());

    return true;
}

bool gcmp::TemporaryDimensionHandler::GetCoordinate(Coordinate3d &curCoord) const
{
    return false;
}

bool TemporaryDimensionHandler::IsInInputState() const
{
    return m_InputState != InputState::None;
}

bool gcmp::TemporaryDimensionHandler::IsInputWidgetEditable() const
{
    return m_pEditor && m_pEditor->hasFocus();
}

void TemporaryDimensionHandler::ResetEditorPosition()
{
    // 需要根据当前状态选用editor位置
    Vector3d editorPos = Vector3d();
    switch (m_InputState)
    {
    case InputState::None:
    {
        HideInputWidget();
        return; // 注意这里是return！
    }
    case InputState::Length:
    {
        editorPos = m_TmpDimData.LengthDimensionPosition;
        break;
    }
    case InputState::Angle:
    {
        editorPos = m_TmpDimData.AngleDimensionPosition;
        break;
    }
    case InputState::Radius:
    {
        editorPos = m_TmpDimData.RadiusDimensionPosition;
        break;
    }
    case InputState::CentralAngle:
    {
        editorPos = m_TmpDimData.CentralAngleDimensionPosition;
        break;
    }
    case InputState::Width:
    {
        editorPos = m_TmpDimData.WidthDimensionPosition;
        break;
    }
    case InputState::Height:
    {
        editorPos = m_TmpDimData.HeightDimensionPosition;
        break;
    }
    default:
        DBG_WARN(L"不该运行至此。",L"GDMPLab",L"2024-03-30");
        return;
    }

    // 设置新位置
    SetEditorPosition(editorPos);
}

void TemporaryDimensionHandler::SetEditorPosition(const Vector3d& posOnView)
{
    if (m_pEditor == nullptr)
    {
        return;
    }
    
    // 设置输入框位置
    int screenX = 0;
    int screenY = 0;
    float depth = 0.0f;
    IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
    UiViewUtility::WorldPositionToScreenPosition(pUIView, posOnView, screenX, screenY, depth);

    QWidget* pGmView = QWidget::find((WId)pUIView->GetUiViewId());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGmView, L"pCtx为空。",L"GDMPLab",L"2024-03-30");
    QPoint curViewGlobalPosOrigin = pGmView->mapToGlobal(QPoint(0, 0));
    QSize size = m_pEditor->size();
    bool isSubUiView = false;
    QObject* pParentWidget = pGmView->parent();
    if (pParentWidget)
    {

#ifdef _GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_
        IUiView* pParentUiView = nullptr;
        QVariant qtVar = pParentWidget->property("uiView");
        if (qtVar.isValid()) {
            pParentUiView = static_cast<gcmp::IUiView*>(qtVar.value<void*>());
        }
#else
        IUiView* pParentUiView = dynamic_cast<IUiView*>(pParentWidget);
#endif // !_GNUF_WIP_REFACTOR_UIDOC_UIVIEW_LOGIC_

        if (pParentUiView)
            isSubUiView = true;             //目前视口属于子UiView,其位置会被移到屏幕以外，导致视口中子控件看不见
    }

    if (isSubUiView)    //此处判断如果是子UIView（即视口的UIView）,由于在GmView中将视口的UIView移到屏幕之外，因此需要在视口UIView子控件显示的时候移回来，SUBUIVIEW_POSITION_OFFSET_X和SUBUIVIEW_POSITION_OFFSET_Y值与GmView需要保持一致
        m_pEditor->move(curViewGlobalPosOrigin.x() + screenX - size.width() / 2 - SUBUIVIEW_POSITION_OFFSET_X, curViewGlobalPosOrigin.y() + screenY - size.height() / 2 - SUBUIVIEW_POSITION_OFFSET_Y);
    else
        m_pEditor->move(curViewGlobalPosOrigin.x() + screenX - size.width() / 2, curViewGlobalPosOrigin.y() + screenY - size.height() / 2);
}

void TemporaryDimensionHandler::CreateEditorWidget()
{
    UpdateUiView();

    // 创建文本输入框
    IUiView* pUIView = IUiDocumentViewManager::Get()->GetUiViewByRuntimeId(m_uiViewId);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIView, L"pUIView为空。",L"GDMPLab",L"2024-03-30");
    QWidget* pGmView = QWidget::find((WId)pUIView->GetUiViewId());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGmView, L"pGmView为空。",L"GDMPLab",L"2024-03-30");
    m_pEditor = pGmView->findChild<TemporaryDimensionHandleEditor*>(QStringLiteral("ViewInputLineEdit"));
    if (nullptr == m_pEditor)
    {
        m_pEditor = NEW_AS_QT_CHILD(TemporaryDimensionHandleEditor, pGmView);
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_pEditor, L"m_pEditor创建失败。",L"GDMPLab",L"2024-03-30");
        m_pEditor->setObjectName(QStringLiteral("ViewInputLineEdit")); // 日志敏感
        m_pEditor->setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint);  
    }

    m_pEditor->installEventFilter(this);
    m_pEditor->setFixedSize(m_TmpDimStyle.EditorWidth, m_TmpDimStyle.EditorHeight);
    m_pEditor->show();
    m_pEditor->activateWindow();
    m_pEditor->setFocus();

    pGmView->installEventFilter(m_pEditor);

    // 设置控件颜色
    m_pEditor->setStyleSheet(
        "QLineEdit{ color:rgba(199, 199, 120, 100%); border:2px solid rgba(199, 199, 120, 100%); font:10pt; border-radius:4px}"
        "QLineEdit:!enabled{ color:rgba(100, 100, 100, 100%);}"
        "QLineEdit:focus{ color:rgba(0, 0, 0, 100%); background:rgba(255, 255, 255, 100%);}"
    );

    // 防止全局Style影响
    m_pEditor->setStyle(QStyleFactory::create("WindowsVista"));

    QColor color = QColor(Qt::white);
    QPalette pal = m_pEditor->palette();
    pal.setColor(QPalette::Base, color);
    m_pEditor->setPalette(pal);

    // 合法性检查助手
    m_opValidateHelper = NEW_AS_OWNER_PTR(LineEditValidateHelper, this);

    // 日志支持
    OwnerPtr<gcmp::IJournalUiObject> opUIObject = gcmp::IJournalUiObject::Create();
    DBG_WARN_AND_RETURN_VOID_UNLESS(opUIObject, L"gcmp::IJournalUiObject::Create()返回空指针",L"GDMPLab",L"2024-03-30");
    opUIObject->SetUiObejct((QObject*)m_pEditor);
    JournalUtils::SetWidgetFlag(opUIObject.get(), gcmp::JournalWidgetFlag::NeedLogDeferredMouseMoveEvents);
}

void TemporaryDimensionHandler::UpdateUiView()
{
    int curViewId = IUiDocumentViewManager::Get()->GetCurrentUiView()->GetId();
    if (m_uiViewId != curViewId)
    {
        m_uiViewId = curViewId;
    }
}

void TemporaryDimensionHandler::DisableIme()
{
    IUiManager* pUiMgr = IUiManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiMgr, L"pUiMgr为空！",L"GDMPLab",L"2024-03-30");
    IApplicationWindow* pUIMainWnd = pUiMgr->GetApplicationWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIMainWnd, L"pUIMainWnd为空",L"GDMPLab",L"2024-03-30");

#ifdef _WINDOWS
    QWidget* pQMainWindow = QWidget::find((WId)(pUIMainWnd->GetApplicationWindowId()));
    if (pQMainWindow)
    {
        HWND hWnd = reinterpret_cast<HWND>(pQMainWindow->winId());
        if (hWnd)
        {
            m_hIMC = ImmAssociateContext(hWnd, NULL);
        }
    }
#endif // _WINDOWS
}

void TemporaryDimensionHandler::EnableIme()
{
    IUiManager* pUiMgr = IUiManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiMgr, L"pUiMgr为空！",L"GDMPLab",L"2024-03-30");
    IApplicationWindow* pUIMainWnd = pUiMgr->GetApplicationWindow();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIMainWnd, L"pUIMainWnd为空",L"GDMPLab",L"2024-03-30");

#ifdef _WINDOWS
    QWidget* pQMainWindow = QWidget::find((WId)(pUIMainWnd->GetApplicationWindowId()));
    if (pQMainWindow)
    {
        HWND hWnd = reinterpret_cast<HWND>(pQMainWindow->winId());
        if (hWnd)
        {
            ImmAssociateContext(hWnd, m_hIMC);
        }
    }
#endif // _WINDOWS
}

void TemporaryDimensionHandler::SetValidRangeOfLength(const Intervald& range)
{
    m_lenValidator.SetBottom(range.GetMin());
    m_lenValidator.SetTop(range.GetMax());
}

void TemporaryDimensionHandler::SetValidRangeOfAngle(const Intervald& range)
{
    m_angValidator.SetBottom(range.GetMin());
    m_angValidator.SetTop(range.GetMax());
}
